#include <iostream>
#include <string>
#include <algorithm>
#include <cmath>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <TROOT.h>
#include <TFile.h>
#include <TTree.h>
#include <TSQLServer.h>
#include <TSQLResult.h>
#include <TSQLRow.h>
#include <TClonesArray.h>

#include "GeomSvc.h"
#include "TriggerRoad.h"

using namespace std;

TSQLResult *makeQuery(TSQLServer *con, string query)
{
  //cout << query << endl;
  return con->Query(query.c_str());
}

int main(int argc, char **argv)
{
  cout << "Exporting Run: " << argv[1] << " to ROOT file: " << argv[2] << endl;

  GeomSvc *p_geomSvc = GeomSvc::instance();
  p_geomSvc->init("geometry_R962");

  Double_t mass, xF, x1, x2;
  Double_t dx,dy,dz;
  Double_t weight;
  Double_t x0, y0, z0;

  Double_t px1, py1, pz1, p1;
  Double_t px2, py2, pz2, p2;

  Int_t nHodoHits1;
  Int_t detectorID1[100];
  Int_t elementID1[100];
  Double_t xp[100], yp[100];

  Int_t nHodoHits2;
  Int_t detectorID2[100];
  Int_t elementID2[100];
  Double_t xm[100], ym[100];

  TFile *saveFile = new TFile(argv[2], "recreate");
  TTree *saveTree = new TTree("save", "save");

  saveTree->Branch("weight", &weight, "weight/D");
  saveTree->Branch("mass", &mass, "mass/D");
  saveTree->Branch("xF", &xF, "xF/D");
  saveTree->Branch("x1", &x1, "x1/D");
  saveTree->Branch("x2", &x2, "x2/D");
  saveTree->Branch("dx", &dx, "dx/D");
  saveTree->Branch("dy", &dy, "dy/D");
  saveTree->Branch("dz", &dz, "dz/D");


  saveTree->Branch("x0", &x0, "x0/D");
  saveTree->Branch("y0", &y0, "y0/D");
  saveTree->Branch("z0", &z0, "z0/D");

  saveTree->Branch("px1", &px1, "px1/D");
  saveTree->Branch("py1", &py1, "py1/D");
  saveTree->Branch("pz1", &pz1, "pz1/D");
  saveTree->Branch("p1", &p1, "p1/D");

  saveTree->Branch("nHodoHits1", &nHodoHits1, "nHodoHits1/I");
  saveTree->Branch("detectorID1", &detectorID1, "detectorID1[nHodoHits1]/I");
  saveTree->Branch("elementID1", &elementID1, "elementID1[nHodoHits1]/I");
  saveTree->Branch("xp", &xp, "xp[nHodoHits1]/D");
  saveTree->Branch("yp", &yp, "yp[nHodoHits1]/D");

  saveTree->Branch("px2", &px2, "px2/D");
  saveTree->Branch("py2", &py2, "py2/D");
  saveTree->Branch("pz2", &pz2, "pz2/D");
  saveTree->Branch("p2", &p2, "p2/D");

  saveTree->Branch("nHodoHits2", &nHodoHits2, "nHodoHits2/I");
  saveTree->Branch("detectorID2", &detectorID2, "detectorID2[nHodoHits2]/I");
  saveTree->Branch("elementID2", &elementID2, "elementID2[nHodoHits2]/I");
  saveTree->Branch("xm", &xm, "xm[nHodoHits2]/D");
  saveTree->Branch("ym", &ym, "ym[nHodoHits2]/D");

  ///Connect to the SQL databases
  TSQLServer *con = TSQLServer::Connect("mysql://seaquel.physics.illinois.edu", "seaguest","qqbar2mu+mu-");
  const char *buf1 = "SELECT trackID1,trackID2,sigWeight,mass,xF,x1,x2,dx,dy,dz FROM %s.mDimuon WHERE acceptAll=1 AND sigWeight>0.0001 ORDER BY eventID LIMIT %d";
  const char *buf2 = "SELECT x0,y0,z0,px0,py0,pz0 FROM %s.mTrack WHERE trackID IN (%d, %d) ORDER BY trackID";
    const char *buf3 = "SELECT trackID,detectorName,elementID,xAtDigiPlane,yAtDigiPlane FROM %s.mDigiHit WHERE trackID IN (%d, %d) AND (detectorName LIKE 'H__'"
      " OR detectorName LIKE 'H4___') ORDER BY trackID,zAtDigiPlane";

    char query[500];
    sprintf(query, buf1, argv[1], atoi(argv[3]));
    TSQLResult *res_dimuon = makeQuery(con, query);



    UInt_t nEntries = res_dimuon->GetRowCount();
    cout << "Totally " << nEntries << " dimuon pairs in this run" << endl;
    for(UInt_t i = 0; i < nEntries; i++)
      {
	if(i % 1000 == 0)
	  {
	    cout << "Converting dimuon pair " << i << endl;
	  }

	TSQLRow *row_dimuon = res_dimuon->Next();

	Int_t trackID1 = atoi(row_dimuon->GetField(0));
	Int_t trackID2 = atoi(row_dimuon->GetField(1));
	weight = atof(row_dimuon->GetField(2));
	mass = atof(row_dimuon->GetField(3));
	xF = atof(row_dimuon->GetField(4));
	x1 = atof(row_dimuon->GetField(5));
	x2 = atof(row_dimuon->GetField(6));
	dx = atof(row_dimuon->GetField(7));
	dy = atof(row_dimuon->GetField(8));
	dz = atof(row_dimuon->GetField(9));



	sprintf(query, buf2, argv[1], trackID1, trackID2);
	TSQLResult *res_track = makeQuery(con, query);



	Int_t nTracks = res_track->GetRowCount();
	if(nTracks != 2)
	  {
	    cout << "Error: more than 2 tracks in one event! " << endl;
	  }

	for(Int_t j = 0; j < nTracks; j++)
	  {
	    TSQLRow *row_track = res_track->Next();

	    x0 = atof(row_track->GetField(0));
	    y0 = atof(row_track->GetField(1));
	    z0 = atof(row_track->GetField(2));
	    if(j == 0)
	      {
		px1 = atof(row_track->GetField(3));
		py1 = atof(row_track->GetField(4));
		pz1 = atof(row_track->GetField(5));
		p1 = sqrt(px1*px1 + py1*py1 + pz1*pz1);
	      }
	    else
	      {
		px2 = atof(row_track->GetField(3));
		py2 = atof(row_track->GetField(4));
		pz2 = atof(row_track->GetField(5));
		p2 = sqrt(px2*px2 + py2*py2 + pz2*pz2);
	      }

	    delete row_track;
	  }



	sprintf(query, buf3, argv[1], trackID1, trackID2);
	TSQLResult *res_hodo = makeQuery(con, query);


	Int_t nHodoHitsAll = res_hodo->GetRowCount();
	nHodoHits1 = 0;
	nHodoHits2 = 0;
	for(Int_t j = 0; j < nHodoHitsAll; j++)
	  {
	    TSQLRow *row_hodo = res_hodo->Next();

	    Int_t trackID = atoi(row_hodo->GetField(0));
	    string detectorName(row_hodo->GetField(1));
	    Int_t elementID = atoi(row_hodo->GetField(2));
	    Double_t x_pos = atof(row_hodo->GetField(3));
	    Double_t y_pos = atof(row_hodo->GetField(4));
	    p_geomSvc->toLocalDetectorName(detectorName, elementID);

	    if(trackID == trackID1)
	      {
		detectorID1[nHodoHits1] = p_geomSvc->getDetectorID(detectorName);
		elementID1[nHodoHits1] = elementID;
		xm[nHodoHits1] = x_pos;
		ym[nHodoHits1] = y_pos;

		++nHodoHits1;
	      }
	    else if(trackID == trackID2)
	      {
		detectorID2[nHodoHits2] = p_geomSvc->getDetectorID(detectorName);
		elementID2[nHodoHits2] = elementID;
		xp[nHodoHits2] = x_pos;
		yp[nHodoHits2] = y_pos;

		++nHodoHits2;
	      }

	    delete row_hodo;
	  }

	saveTree->Fill();

	delete row_dimuon;
	delete res_track;
	delete res_hodo;
      }

    delete res_dimuon;
    delete con;

    saveFile->cd();
    saveTree->Write();
    saveFile->Close();

    return 1;
}
